package io.kblog.support

import com.fasterxml.jackson.annotation.JsonFilter
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.BeanPropertyFilter
import com.fasterxml.jackson.databind.ser.FilterProvider
import com.fasterxml.jackson.databind.ser.PropertyFilter
import com.fasterxml.jackson.databind.ser.PropertyWriter
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter
import java.util.*
import kotlin.reflect.KClass


@JsonFilter(value = "JacksonFilter")
class JacksonJsonFilter : FilterProvider() {
    private var includeMap: MutableMap<KClass<*>, Set<String>> = HashMap()
    private var filterMap: MutableMap<KClass<*>, Set<String>> = HashMap()
    private var clazzs: Map<KClass<*>?, Map<String,String>>?=null

    fun include(clazzs: Map<KClass<*>?, Map<String,String>>?,type: KClass<*>?, fields: Array<String>) {
        addToMap(clazzs,includeMap, type, fields)
    }

    fun filter(clazzs: Map<KClass<*>?, Map<String,String>>?,type: KClass<*>?, fields: Array<String>) {
        addToMap(clazzs,filterMap, type, fields)
    }

    private fun addToMap(clazzs: Map<KClass<*>?, Map<String,String>>?,map: MutableMap<KClass<*>, Set<String>>, type: KClass<*>?, fields: Array<String>) {
        val fieldSet = (map as Map<KClass<*>, MutableSet<String>>).getOrDefault(type, HashSet())
        fieldSet.addAll(fields)
        map[type!!] = fieldSet
        this.clazzs=clazzs
    }

    override fun findFilter(filterId: Any): BeanPropertyFilter {
        throw UnsupportedOperationException("Access to deprecated filters not supported")
    }

    override fun findPropertyFilter(filterId: Any, valueToFilter: Any?): PropertyFilter {
        return object : SimpleBeanPropertyFilter() {
            override fun serializeAsField(pojo: Any, jgen: JsonGenerator, prov: SerializerProvider, writer: PropertyWriter) {
                if (apply(pojo.javaClass.kotlin, writer.name)) {
                    writer.serializeAsField(pojo, jgen, prov)
                } else if (!jgen.canOmitFields()) {
                    writer.serializeAsOmittedField(pojo, jgen, prov)
                }
            }
        }
    }

    /**
     * 用于判断pojo的当前属性"name"是否在@JSON标记的条件中（在include里或不在filter里），符合条件会把此属性及其值放入json中
     */
    fun apply(type: KClass<*>, name: String) = includeMap[type].run { this!= null && this.contains(name) }||filterMap[type].run { this!= null && !this.contains(name) }||(includeMap[type] == null && filterMap[type] == null).run{clazzs?.filter {type.java.superclass.name==it.key!!.java.name&&(it.value.getValue("include").run {this.isNotBlank()&&this.contains(name) }||it.value.getValue("filter").run { this.isNotBlank()&&!this.contains(name)})}!!.any()}
}